﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

// 类名: MyCurveDrawScript
// 功能介绍：
//     1、曲线绘制脚本
//     2、
//     3、
//     4、
// 使用事项：
//     1、左键点下开始绘制，抬起结束
//     2、shift按下，绘制直线
//     3、当shift按下时，左键的按下与抬起为切换直线绘制，右键按下结束绘制
//     4、
// 作者: penguin_ku
// 版权：Copyright (C) 3shine
// 时间: 2013/9/21 23:33:22
// 版本: V1.0.0.0
// 修改列表：
//     时间         修改人        备注
//
//
public class MyCurveDrawScript : MonoBehaviour
{
    #region 公有成员

    public Texture PointTexture;                  //点图
    public Vector2 PointSize;                       //点大小，影响直线的宽度以及密度
    public int Density;                             //密度

    #endregion

    #region 反射成员

    // Initialize Property
    void Awake()
    {
        InitializeLineProperty();   // 初始化线属性
    }

    // Load Resources
	void Start () 
    {
        CheckPropertyValid();
	}
	
	// Do Action
	void Update () 
    {
        UpdateLineInfo();           //更新线信息
    }

    // Draw Pixel
    void OnGUI()
    {
        DrawLine();         //绘制线
    }

    #endregion

    #region 线

    List<MyLine> _lineArray;                        //线集合
    MyLine _currLine;                               //当前线

    /// <summary>
    /// 检查曲线属性设置合法性
    /// </summary>
    void CheckPropertyValid()
    {
        if (PointTexture == null)
        {
            PointTexture = Resources.Load("PointImage", typeof(Texture)) as Texture;
        }
        if (PointSize.x == 0)
        {
            PointSize.x = 2;
        }
        if (PointSize.y == 0)
        {
            PointSize.y = 2;
        }
        if (Density == 0)
        {
            Density = 6;
        }
    }

    /// <summary>
    /// 初始化线属性
    /// </summary>
    void InitializeLineProperty()
    {
        _lineArray = new List<MyLine>();
    }

    /// <summary>
    /// 更新线记录信息
    /// </summary>
    void UpdateLineInfo()
    {
        bool isShift = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
        // 鼠标左键按下开始记录新线
        if (Input.GetMouseButtonDown(0))
        {
            _currLine = new MyLine();
            _lineArray.Add(_currLine);
        }
        //鼠标左键抬起，根据shift键是否按下分支
        if (Input.GetMouseButtonUp(0))
        {
            if (isShift)
            {
                _currLine = new MyLine();
                _lineArray.Add(_currLine);
            }
            else
            {
                _currLine = null;
            }
        }
        // 鼠标右键抬起，在shift模式下，为结束绘制
        if (Input.GetMouseButtonUp(1) && isShift)
        {
            _currLine = null;
        }

        //记录新线信息
        if (_currLine != null)
        {
            Vector2 point = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
            if ((Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) && _currLine.PointArray.Count != 0)
            {
                Vector2 pointBegin =  _currLine.PointArray[0];
                _currLine.PointArray.Clear();
                _currLine.PointArray.Add(pointBegin);
                
            }
            _currLine.PointArray.Add(point);
        }
    }

    /// <summary>
    /// 绘制线
    /// </summary>
    void DrawLine()
    {
        foreach (var item in _lineArray)
        {
            DrawLine(item.PointArray, PointSize, PointTexture);
        }
    }

    /// <summary>
    /// 绘制线
    /// </summary>
    /// <param name="p_pointArray"></param>
    /// <param name="p_lineTexture"></param>
    void DrawLine(List<Vector2> p_pointArray, Vector2 p_pointSize, Texture p_pointTexture)
    {
        List<Vector2> pointArray = CurveMatching(p_pointArray, p_pointSize);
        foreach (var item in pointArray)
        {
            GUI.DrawTexture(new Rect(item.x, item.y, p_pointSize.x, p_pointSize.y), PointTexture);
        }
    }

    /// <summary>
    /// 曲线拟合
    /// </summary>
    /// <remarks>此处使用的为最简单的梯形拟合，如果为精确可考虑使用牛顿插值或者拉格拉日等算法，具体算法可google其实现逻辑</remarks>
    List<Vector2> CurveMatching(List<Vector2> p_pointArray, Vector2 p_pointSize)
    {
        List<Vector2> pointArray = new List<Vector2>();
        //拟合公式 插值
        for (int i = 0; i < p_pointArray.Count - 1; i++)
        {
            // 拟合点
            List<Vector2> pointArrayTemp = new List<Vector2>();
            Vector2 pointBegin = p_pointArray[i];
            Vector2 pointEnd = p_pointArray[i + 1];

            float distance = Mathf.Sqrt(Mathf.Pow((pointEnd.y - pointBegin.y), 2) + Mathf.Pow((pointEnd.x - pointBegin.x), 2));
            float cell = Mathf.Sqrt(Mathf.Pow((p_pointSize.y), 2) + Mathf.Pow((p_pointSize.x), 2));
            int pixel = (int)(distance / cell) * Density;

            pointArrayTemp.Add(pointBegin);

            float xstep = pointEnd.x - pointBegin.x == 0 ? 0 : (pointEnd.x - pointBegin.x) / pixel;
            float ystep = pointEnd.y - pointBegin.y == 0 ? 0 : (pointEnd.y - pointBegin.y) / pixel;
            for (int k = 1; k < pixel - 1; k++)
            {
                Vector2 pointTemp = new Vector2();
                pointTemp.x = pointBegin.x + xstep * k;
                pointTemp.y = pointBegin.y + ystep * k;
                pointArrayTemp.Add(pointTemp);
            }
            pointArrayTemp.Add(pointEnd);

            pointArray.AddRange(pointArrayTemp);
        }

        return pointArray;
    }

    #endregion

}

/// <summary>
/// 线结构
/// </summary>
public class MyLine
{
    /// <summary>
    /// 设置或获取点集合
    /// </summary>
    public List<Vector2> PointArray { private set; get; }

    /// <summary>
    /// 构造函数
    /// </summary>
    public MyLine()
    {
        PointArray = new List<Vector2>();
    }
}